﻿using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Security.Claims;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Memory;
using ServiceStack.OrmLite;
using WebCoreAdmin.Common;

namespace WebCoreAdmin.Controllers
{
    [AllowAnonymous]
    public class AccountController : Controller
    {
        private OrmLiteConnectionFactory Fac { get; }
        private MD5 Md5 { get; set; }
        private RsaHelper RsaHelper { get; set; }
        private IMemoryCache Cache { get; set; }
        public AccountController(MD5 md5, OrmLiteConnectionFactory fac,RsaHelper rsa, IMemoryCache cache)
        {
            Fac = fac;
            Md5 = md5;
            RsaHelper = rsa;
            Cache = cache;
        }
       
        [HttpGet]
        [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
        public async Task<IActionResult> Login()
        {
            await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
            return View();
        }
        [HttpPost]
        [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
        public async Task<IActionResult> Login(string user,string password,string verifycode, string returnUrl)
        {   
            ViewData["error"] = "";

            if (string.IsNullOrWhiteSpace(user))
            {
                ViewData["error"] = "用户名为空！";
                return View();
            }
            if (string.IsNullOrWhiteSpace(password))
            {
                ViewData["error"] = "密码为空！";
                return View();
            }
            if (string.IsNullOrWhiteSpace(verifycode))
            {
                ViewData["error"] = "验证码为空！";
                return View();
            }

            //            HttpContext.Request.Cookies.TryGetValue("verifycode", out string code);
            //            if (EncryptWithMd5(verifycode.ToLower())!=code)
            //            {
            //                ViewData["error"] = "验证码错误！";
            //                return View();
            //            }
            HttpContext.Request.Cookies.TryGetValue("verifycode", out string guid);
            var cacheExist=Cache.TryGetValue(guid, out string codeCache);
            if (!cacheExist)
            {
                ViewData["error"] = "验证码超时！";
                return View();
            }
            if (codeCache!=verifycode)
            {
                ViewData["error"] = "验证码错误！";
                return View();
            }

            //todo:验证密码
            password = RsaHelper.Decrypt(password);
            if (false)
            {
                ViewData["error"] = "用户名密码错误！";
                return View();
            }
            
            var identity = new ClaimsIdentity(CookieAuthenticationDefaults.AuthenticationScheme);
            identity.AddClaim(new Claim(ClaimTypes.Name, user));
            identity.AddClaim(new Claim(ClaimTypes.Role, "1"));
            identity.AddClaim(new Claim(ClaimTypes.Role, "2"));
            await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(identity));
            if (!string.IsNullOrEmpty(returnUrl) && Url.IsLocalUrl(returnUrl))
            {
                return Redirect(returnUrl);
            }
            return RedirectToAction("Index", "Home");
        }
        [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
        public async Task<IActionResult> Logout()
        {
            await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
            return RedirectToAction("Login");
        }
        [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
        public IActionResult GetVerifyCode()
        {
            //            using (var stream = Create(out string code))
            //            {
            //                var buffer = stream.ToArray();
            //                Cache.Set(HttpContext.Connection.Id, code.ToLower(),TimeSpan.FromSeconds(30));
            //                Response.Cookies.Append("verifycode", EncryptWithMd5(code.ToLower()));
            //                return File(buffer, "image/jpeg");
            //            }
            using (var stream = Create(out string code))
            {
                var buffer = stream.ToArray();
                string guid = Guid.NewGuid().ToString();
                Cache.Set(guid, code.ToLower(), TimeSpan.FromSeconds(30));
                Response.Cookies.Append("verifycode", guid);
                return File(buffer, "image/jpeg");
            }

        }
        public string EncryptWithMd5(string source)
        {
            byte[]        sor    = Encoding.UTF8.GetBytes(source);
            byte[]        result = Md5.ComputeHash(sor);
            StringBuilder strbul = new StringBuilder(40);
            foreach (var t in result)
            {
                strbul.Append(t.ToString("x2")); //加密结果"x2"结果为32位,"x3"结果为48位,"x4"结果为64位
            }
            return strbul.ToString();
        }

        private static string RndNum(int vcodeNum)
        {
            //验证码可以显示的字符集合  
            string Vchar = "0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,g,h,i,j,k,l,m,n,p"      +
                           ",q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,P,P,Q" +
                           ",R,S,T,U,V,W,X,Y,Z";
            string[] VcArray = Vchar.Split(new Char[] { ',' }); //拆分成数组   
            string   code    = "";                              //产生的随机数  
            int      temp    = -1;                              //记录上次随机数值，尽量避避免生产几个一样的随机数  

            Random rand = new Random();
            //采用一个简单的算法以保证生成随机数的不同  
            for (int i = 1; i < vcodeNum + 1; i++)
            {
                if (temp != -1)
                {
                    rand = new Random(i * temp * unchecked((int)DateTime.Now.Ticks)); //初始化随机类  
                }
                int t = rand.Next(61); //获取随机数  
                if (temp != -1 && temp == t)
                {
                    return RndNum(vcodeNum); //如果获取的随机数重复，则递归调用  
                }
                temp =  t;          //把本次产生的随机数记录起来  
                code += VcArray[t]; //随机数的位数加一  
            }
            return code;
        }
        public static MemoryStream Create(out string code, int numbers = 4)
        {
            code = RndNum(numbers);
            //Bitmap img = null;
            //Graphics g = null;
            MemoryStream ms     = null;
            Random       random = new Random();
            //验证码颜色集合  
           
            Color[] c = { Color.Black, Color.Red, Color.DarkBlue, Color.Green, Color.Orange, Color.Brown, Color.DarkCyan, Color.Purple };

            //验证码字体集合
            string[] fonts = { "Verdana", "Microsoft Sans Serif", "Comic Sans MS", "Arial", "宋体" };


            using (var img = new Bitmap((int)code.Length * 18, 32))
            {
                using (var g = Graphics.FromImage(img))
                {
                    g.Clear(Color.White); //背景设为白色

                    //在随机位置画背景点  
                    for (int i = 0; i < 100; i++)
                    {
                        int x = random.Next(img.Width);
                        int y = random.Next(img.Height);
                        g.DrawRectangle(new Pen(Color.LightGray, 0), x, y, 1, 1);
                    }
                    //验证码绘制在g中  
                    for (int i = 0; i < code.Length; i++)
                    {
                        int   cindex = random.Next(7);                              //随机颜色索引值  
                        int   findex = random.Next(5);                              //随机字体索引值  
                        Font  f      = new Font(fonts[findex], 15, FontStyle.Bold); //字体  
                        Brush b      = new SolidBrush(c[cindex]);                   //颜色  
                        int   ii     = 4;
                        if ((i + 1) % 2 == 0) //控制验证码不在同一高度  
                        {
                            ii = 2;
                        }
                        g.DrawString(code.Substring(i, 1), f, b, 3 + (i * 12), ii); //绘制一个验证字符  
                    }
                    ms = new MemoryStream();        //生成内存流对象  
                    img.Save(ms, ImageFormat.Jpeg); //将此图像以Png图像文件的格式保存到流中  
                }
            }

            return ms;
        }
    }
}
